#ifndef ARC_CACHE_H
#define ARC_CACHE_H

#include "../cachePolicy.h"
#include "./ARCLFUPart.h"
#include "./ARCLRUPart.h"
#include <memory>

using namespace std;

namespace Cache {

template <typename Key, typename Value> class ArcCache : public cachePolicy<Key, Value> {
public:
    explicit ArcCache(size_t capacity = 10, size_t transformThreshold = 2)
        : capacity_(capacity), transformThreshold_(transformThreshold),
          lruPart_(make_unique<ArcLRUPart<Key, Value>>(capacity, transformThreshold)),
          lfuPart_(make_unique<ArcLFUPart<Key, Value>>(capacity, transformThreshold)) {
        // cout << "Successful ArcCache Construct" << endl;
    }

    ~ArcCache() override = default;

    void put(Key k, Value v) override {
        bool inGhost = checkGhostCaches(k);
        if (inGhost)
            lruPart_->put(k, v);
        else {
            if (lruPart_->put(k, v))
                lfuPart_->put(k, v);
            else
                lruPart_->put(k, v);
        }
    }

    bool get(Key k, Value &v) override {
        checkGhostCaches(k);

        bool shouldTransform = false;
        if (lruPart_->get(k, v, shouldTransform)) {
            if (shouldTransform)
                lfuPart_->put(k, v);
            return true;
        }
        return lfuPart_->get(k, v);
    }

    Value get(Key k) override {
        Value value{};
        get(k, value);
        return value;
    }

private:
    bool checkGhostCaches(Key k) {
        bool inGhost = false;
        if (lruPart_->checkGhost(k)) {
            inGhost = true;
            if (lfuPart_->decreaseCapacity())
                lruPart_->increaseCapacity();
        } else if (lfuPart_->checkGhost(k)) {
            inGhost = true;
            if (lruPart_->decreaseCapacity())
                lfuPart_->increaseCapacity();
        }
        return inGhost;
    }

    size_t capacity_;
    size_t transformThreshold_;
    unique_ptr<ArcLRUPart<Key, Value>> lruPart_;
    unique_ptr<ArcLFUPart<Key, Value>> lfuPart_;
};

} // namespace Cache

#endif